package com.higgins.eventtracking.server;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.jdo.Query;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import com.higgins.eventtracking.client.DietTrackingService;
import com.higgins.eventtracking.client.SecurityAccessDeniedException;
import com.higgins.eventtracking.client.dto.AssetDTO;
import com.higgins.eventtracking.client.dto.FinanceGoalDTO;
import com.higgins.eventtracking.client.dto.InventoryDTO;
import com.higgins.eventtracking.client.dto.MealDTO;
import com.higgins.eventtracking.server.dataModel.Asset;
import com.higgins.eventtracking.server.dataModel.Consumption;
import com.higgins.eventtracking.server.dataModel.FinanceGoal;
import com.higgins.eventtracking.server.dataModel.HealthAlert;
import com.higgins.eventtracking.server.dataModel.HealthEvent;
import com.higgins.eventtracking.server.dataModel.Inventory;
import com.higgins.eventtracking.server.dataModel.InventoryAlert;
import com.higgins.eventtracking.server.dataModel.Meal;
import com.higgins.eventtracking.server.dataModel.TrackingEvent;


public class DietTrackingDataService extends GenericDataStoreService implements DietTrackingService	{

	public Boolean insertMeal(String meal, String mealType, Double calories, Double protein, Double fat, Double water)	{
		pm.makePersistent(new Meal(meal, mealType, calories, protein, fat, water));
		return true;
	}
	@Override
	public Boolean insertInventory(InventoryDTO dto)
			throws IllegalArgumentException {
		Inventory inventory = new Inventory();
		inventory.update(dto);
		pm.makePersistent(inventory);
		return true;
	}

	
	public Boolean insertConsumption(Date timestamp, String meal, Double calories, Double protein, Double fat, Double water)	{
		pm.makePersistent(new Consumption(timestamp, meal, calories, protein, fat, water));
		return true;
	}

   public Boolean hasEaten(int hours) {
        Date startDate = DateUtility.addHours(new Date(), -hours);
        List<Consumption> results; 
        Query query;
        query=pm.newQuery(Consumption.class);
        query.setFilter("timestamp > startDateParam");
        query.declareParameters("java.util.Date startDateParam");
        results = (List<Consumption>) query.execute(startDate);
        for (Consumption consumption:results)   {
            if (consumption.getCalories() > 10) {
                return true;
            }
        }
        return false;
    }
    

	
	public List<MealDTO> retrieveMeals()	{
		Query query=pm.newQuery(Meal.class);
//		query.setOrdering("timestamp desc");
		List<Meal> meals = (List<Meal>)query.execute();
		List<MealDTO> mealDTOs = new ArrayList<MealDTO>();
		for (Meal meal:meals)	{
			MealDTO mealDTO = meal.toDTO();
			mealDTOs.add(mealDTO);
		}
		return mealDTOs;
	}
	public Boolean retrieveMasterSwitch()	{
		Query query=pm.newQuery(HealthAlert.class);
		query.setFilter("eventType==eventTypeParam");
		query.declareParameters("String eventTypeParam");
		List<HealthAlert> healthAlerts = (List<HealthAlert>)query.execute("MasterSwitch");
		if (healthAlerts.size() > 0)	{
			HealthAlert masterSwitch = healthAlerts.get(0);
			return masterSwitch.getOnOff();
		}
		return false;
	}
	public List<HealthAlert> retrieveHealthAlerts()	{
		Query query=pm.newQuery(HealthAlert.class);
		query.setFilter("onOff==true");
		List<HealthAlert> healthAlerts = (List<HealthAlert>)query.execute();
		return healthAlerts;
	}
	
	public List<InventoryAlert> retrieveInventoryAlerts()	{
		Query query=pm.newQuery(InventoryAlert.class);
		query.setFilter("onOff==true");
		List<InventoryAlert> inventoryAlerts = (List<InventoryAlert>)query.execute();
		return inventoryAlerts;
	}
	
	public String sendInventoryAlert(InventoryAlert inventoryAlert)	{
		String name = inventoryAlert.getName();
		String returnString = null;
		if (name==null)	{
			return null;
		}
		int hour = DateUtility.getHour(new Date());
		if (inventoryAlert.getHour().equals(hour))	{
			if (name.equals("Breakfast"))	{
				String breakfast = retrieveBreakfastInventory();
				if (breakfast!=null)	{
					return name + ": " + breakfast;
				} else {
					return "No food available for breakfast";
				}
			} else if (name.equals("Main"))	{
				String main = retrieveMainInventory();
				if (main!=null)	{
					return name + ": " + main;
				} else {
					return "No food available for main";
				}
			} else if (name.equals("Snack"))	{
				String snack = retrieveSnackInventory();
				if (snack!=null)	{
					return name + ": " + snack;
				} else {
					return "No food available for snack";
				}
			} else if (name.equals("Throw Away"))	{
				String throwAways = retrieveThrowAwayInventory();
				if (throwAways!=null)	{
					return name + ": " + throwAways;
				} 
			}
		} 
		return null;
	}
	private String retrieveBreakfastInventory()	{
		Query query=pm.newQuery(Inventory.class);
		query.setOrdering("sellByDate asc");
		query.setFilter("breakfast==breakfastParam");
		query.declareParameters("Boolean breakfastParam");
		List<Inventory> inventorys = (List<Inventory>)query.execute(true);
		if (inventorys.size()>0)	{
			Inventory inv = inventorys.get(0);
			return inv.getName();
		}
		return null;
	}
	private String retrieveMainInventory()	{
		Query query=pm.newQuery(Inventory.class);
		query.setOrdering("sellByDate asc");
		query.setFilter("main==mainParam");
		query.declareParameters("Boolean mainParam");
		List<Inventory> inventorys = (List<Inventory>)query.execute(true);
		if (inventorys.size()>0)	{
			Inventory inv = inventorys.get(0);
			return inv.getName();
		}
		return null;
	}
	private String retrieveSnackInventory()	{
		Query query=pm.newQuery(Inventory.class);
		query.setOrdering("sellByDate asc");
		query.setFilter("snack==snackParam");
		query.declareParameters("Boolean snackParam");
		List<Inventory> inventorys = (List<Inventory>)query.execute(true);
		if (inventorys.size()>0)	{
			Inventory inv = inventorys.get(0);
			return inv.getName();
		}
		return null;
	}
	private String retrieveThrowAwayInventory()	{
		Query query=pm.newQuery(Inventory.class);
		query.setFilter("sellByDate < sellByDateParam");
		query.declareParameters("Date sellByDateParam");
		List<Inventory> inventorys = (List<Inventory>)query.execute(new Date());
		String returnString = null;
		for (Inventory inventory:inventorys)	{
			returnString = returnString!=null?returnString + "; "+ inventory.getName():inventory.getName();
		}
		return returnString;
	}
	public boolean sendHealthAlert(HealthAlert healthAlert)	{
		if (healthAlert.getEventType()!=null && healthAlert.getEventName()!=null)	{
			if (healthAlert.getEventType().equals("ConsumptionEvent"))	{
				return sendConsumptionEvent(healthAlert);
			} else if (healthAlert.getEventType().equals("HealthEvent"))	{
				return sendHealthEvent(healthAlert);
			} else if (healthAlert.getEventType().equals("TrackingEvent"))	{
				return sendTrackingEvent(healthAlert);
			}
		}
		return false;
	}
	public boolean sendConsumptionEvent(HealthAlert healthAlert)	{
		if (checkTime(healthAlert))	{
			Query query=pm.newQuery(Consumption.class);
			query.setOrdering("timestamp desc");
			query.setFilter("timestamp>=dateParam && meal==mealParam");
			query.declareParameters("java.util.Date dateParam, String mealParam");
			query.declareParameters("java.util.Date dateParam, String mealParam");
			Date dateParam = getDateOfLastCheck(healthAlert);
			List<Consumption> meals = (List<Consumption>)query.execute(dateParam, healthAlert.getEventName());
			return meals.size()==0;
		} 
		return false;
	}
	private boolean checkTime(HealthAlert healthAlert)	{
		Double hourOfAlert = healthAlert.getHourOfAlert();
		Calendar cal = Calendar.getInstance();
		Integer hourOfDayInt = cal.get(Calendar.HOUR_OF_DAY);
		Integer minuteOfHourInt = cal.get(Calendar.MINUTE);
		Double hourOfDay = Double.parseDouble(hourOfDayInt.toString());
		Double minuteOfHour = Double.parseDouble(minuteOfHourInt.toString());
		if (hourOfAlert!=null && hourOfAlert>0.0)	{
			if (hourOfDay.equals(hourOfAlert))	{
				if (minuteOfHour < 15.0)	{
					return true;
				}
			}
		} else {
			return true;
		}
		return false;
	}
	public boolean sendHealthEvent(HealthAlert healthAlert)	{
		if (checkTime(healthAlert))	{
			Query query=pm.newQuery(HealthEvent.class);
			query.setOrdering("timestamp desc");
			query.setFilter("timestamp>=dateParam && healthEventType==healthEventParam");
			query.declareParameters("java.util.Date dateParam, String healthEventParam");
			Date dateParam = getDateOfLastCheck(healthAlert);
			List<HealthEvent> healthEvents = (List<HealthEvent>)query.execute(dateParam, healthAlert.getEventName());
			return healthEvents.size()==0;
		}
		return false;
	}	
	public boolean sendTrackingEvent(HealthAlert healthAlert)	{
		if (checkTime(healthAlert))	{
			if (healthAlert.getEventName()!=null && healthAlert.getEventName().equals("Cardio"))	{
				Query query=pm.newQuery(TrackingEvent.class);
				query.setOrdering("timestamp desc");
				query.setFilter("timestamp>=dateParam && (eventType==eventParamOne || eventType==eventParamTwo)");
				query.declareParameters("java.util.Date dateParam, String eventParamOne, String eventParamTwo");
				Date dateParam = getDateOfLastCheck(healthAlert);
				List<TrackingEvent> meals = (List<TrackingEvent>)query.execute(dateParam, "Running", "Cycling");
				return meals.size()==0;
			} else {
				Query query=pm.newQuery(TrackingEvent.class);
				query.setOrdering("timestamp desc");
				query.setFilter("timestamp>=dateParam && eventType==eventParam");
				query.declareParameters("java.util.Date dateParam, String eventParam");
				Date dateParam = getDateOfLastCheck(healthAlert);
				List<TrackingEvent> meals = (List<TrackingEvent>)query.execute(dateParam, healthAlert.getEventName());
				return meals.size()==0;
			}
		}
		return false;
	}
	private Date getDateOfLastCheck(HealthAlert healthAlert)	{
		Date now = new Date();
		Date lastChecked = now;
		Integer every = healthAlert.getEvery();
		String timePeriod = healthAlert.getTimePeriod();
		
		if (timePeriod.equals("Days"))	{
			lastChecked = DateUtility.addDays(now, -every);
		} else if (timePeriod.equals("Hours"))	{
			lastChecked = DateUtility.addHours(now, -every);
		}
		return lastChecked;
	}
	public List<Consumption> retrieveConsumption(Date start, Date end)	{
		Query query=pm.newQuery(Consumption.class);
		query.setOrdering("timestamp desc");
		query.setFilter("timestamp>=startParam && timestamp<=endParam");
		query.declareParameters("java.util.Date startParam, java.util.Date endParam");
		List<Consumption> meals = (List<Consumption>)query.execute(start, end);
		return meals;
	}
	
	
	@Override
	public Double retrieveCaloriesToday() throws IllegalArgumentException {
		Date date = DateUtility.getStartOfDay(new Date());
		Double calories = 0.0;
		Query query=pm.newQuery(Consumption.class);
		query.setFilter("timestamp >= dateParam");
		query.declareParameters("java.util.Date dateParam");
		//		query.setOrdering("timestamp desc");
		List<Consumption> consumptions = (List<Consumption>)query.execute(date);
		for (Consumption consumption:consumptions)	{
			calories = calories + consumption.getCalories();
		}
		return calories;
	}

	@Override
	public Double retrieveProteinToday() throws IllegalArgumentException {
		Date date = DateUtility.getStartOfDay(new Date());
		Double protein = 0.0;
		Query query=pm.newQuery(Consumption.class);
		query.setFilter("timestamp >= dateParam");
		query.declareParameters("java.util.Date dateParam");
//		query.setOrdering("timestamp desc");
		List<Consumption> consumptions = (List<Consumption>)query.execute(date);
		for (Consumption consumption:consumptions)	{
			protein = protein + consumption.getProtein();
		}
		return protein;
	}

	@Override
	public Double retrieveFatToday() throws IllegalArgumentException {
		Date date = DateUtility.getStartOfDay(new Date());
		Double fat = 0.0;
		Query query=pm.newQuery(Consumption.class);
		query.setFilter("timestamp >= dateParam");
		query.declareParameters("java.util.Date dateParam");
//		query.setOrdering("timestamp desc");
		List<Consumption> consumptions = (List<Consumption>)query.execute(date);
		for (Consumption consumption:consumptions)	{
			fat = fat + consumption.getFat();
		}
		return fat;
	}

	@Override
	public Double retrieveWaterToday() throws IllegalArgumentException {
		Date date = DateUtility.getStartOfDay(new Date());
		Double water = 0.0;
		Query query=pm.newQuery(Consumption.class);
		query.setFilter("timestamp >= dateParam");
		query.declareParameters("java.util.Date dateParam");
//		query.setOrdering("timestamp desc");
		List<Consumption> consumptions = (List<Consumption>)query.execute(date);
		for (Consumption consumption:consumptions)	{
			water = water + consumption.getWater();
		}
		return water;
	}

}
